/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

const startTime = Number(process.hrtime.bigint());

import crypto from 'crypto';
import fs from 'fs';
import os from 'os';
import path from 'path';

import { CacheStoreManager, MAIN_THREAD } from '@ohos/hvigor';
import { CompileEvent, MSGPACK_COMPILE_CACHE_DIR_NAME, ProjectConfig, runArkPack, runEtsStandaloneChecker } from '@ohos/hvigor-arkts-compose';
import { Level, levels } from 'log4js';

import { ECM } from '../../error/error-code-map.js';
import { handleLogs, OhosLogger } from '../../utils/log/ohos-logger.js';
import { getSoDefaultContextInfo, soLibsPattern } from '../generate-pkg-context-info.js';
import { generateLoaderEnv } from './util.js';

const endTime = Number(process.hrtime.bigint());

const log: OhosLogger = OhosLogger.getLogger('Ark');
let level: Level = levels.DEBUG;

export const errorCallback = (error: Error) => {
  (error as Error & { dece: string }).dece = ECM.DECE.ARKTS_COMPILER;
};

let hasLoadDependencies = false;

export const run = async (config: ProjectConfig, cacheStoreManager?: CacheStoreManager): Promise<CompileEvent[] | Error> => {
  generateLoaderEnv(config);
  level = levels.getLevel(config.level!, levels.INFO);
  log.setLevel(level);
  if (config.pkgContextInfo) {
    // 针对pkgContextInfo中读取so的场景，如果sdk读取so读取不到时提供一个默认模板
    config.pkgContextInfo = new Proxy(config.pkgContextInfo, {
      get (target, key) {
        if (typeof key !== 'string') {
          return undefined;
        }
        if (soLibsPattern.test(key) && !target[key]) {
          return getSoDefaultContextInfo(key);
        }
        return target[key];
      },
    });
  }
  return new Promise((resolve) => {
    runArkPack(config, errorCallback, undefined, undefined, log, cacheStoreManager)
      .then((arkCompileResult) => {
        if (arkCompileResult.isSuccess) {
          handleLogs(arkCompileResult.compileLogEvents, log, level);
          !config.isMainThread && !hasLoadDependencies && arkCompileResult.compileEvents.push(getLoadDependencyEvent());
          resolve(arkCompileResult.compileEvents);
        } else {
          resolve(arkCompileResult.error!);
        }
      })
      .catch((reason) => {
        const compileCacheFilePath = path.resolve(config.cachePath ?? '', MSGPACK_COMPILE_CACHE_DIR_NAME);
        fs.rmSync(compileCacheFilePath, { recursive: true, force: true });
        throw reason;
      })
      .finally(() => {
        log.debug(`Ark compile task finished.finished time is ${process.hrtime.bigint()}`);
      });
  });
};

export const runArkLint = async (config: { config: ProjectConfig; entry: Record<string, unknown> }) => {
  generateLoaderEnv(config.config);
  const logs = await runEtsStandaloneChecker(config);
  level = levels.getLevel(config.config.level!, levels.INFO);
  handleLogs(logs, log, level);
  const errorEvents = logs.filter((message) => message.level === 'error');
  if (errorEvents.length > 0) {
    const errorMessage: string = errorEvents.map((item) => item.msg).join(os.EOL);
    log._buildError(`ArkTS lint errors.${os.EOL}${errorMessage}`)._printErrorAndExit();
    log.printErrorExit('ARKTS_LINT_ERRORS', [errorMessage]);
  }
};

/**
 * 获取加载依赖模块对应的事件
 */
function getLoadDependencyEvent(): CompileEvent {
  hasLoadDependencies = true;
  return new CompileEvent(crypto.randomUUID(), 'load compilation dependencies', process.pid, MAIN_THREAD, 0, 0)
    .setStartTime(startTime)
    .setEndTime(endTime)
    .setState('success');
}
